﻿using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Core.WireProtocol.Messages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace OkTool.Db.NoSql.Mongo
{
    /// <summary>
    /// 当前程序集,其他程序集不能访问
    /// </summary>
    public class MongoDS
    {
        /// <summary>
        /// 当前mogon对象
        /// </summary>
        private IMongoClient Mongo;

        /// <summary>
        /// 当前数据库
        /// </summary>
        private  IMongoDatabase Database;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="connectionString"><para>标准的连接字符串：mongodb://username:password@host[:port]/defaultauthdb?[options]</para>
        /// <para>username:password@：用户名与密码，如果服务开启了用户认证，那么可以在连接字符串中写入，否则可以不写。</para>
        /// <para>host[:port]：要连接的服务的主机名(或IP地址)和端口，端口可以不写，默认为27017</para>
        /// <para>/defaultauthdb：创建登录用户时所用的数据库，登录时会到该数据库中进行用户认证。如果连接字符串中没有写明</para>
        /// <para>username:password@，此段可以不写，如果连接字符串中写明了username:password@但是没有写明数据库，那么将会到admin数据库中进行用户认证。</para>
        /// <para>?[options]：连接选项，一般不写直接用默认的就可以了。</para>
        /// </param>
        /// <param name="dbName">数据库,不存在,自动创建</param>
        public  MongoDS(string connectionString, string dbName)
        {
            Mongo = new MongoClient(connectionString);
            //Database = Mongo.GetDatabase(new MongoUrlBuilder(connectionString).DatabaseName);
            Database = Mongo.GetDatabase(dbName);
        }

        /// <summary>
        /// 获得Mongo客户端对象
        /// </summary>
        /// <returns></returns>
        public IMongoClient GetMongo()
        {
            return Mongo;
        }

        /// <summary>
        /// 获得Db
        /// </summary>
        /// <returns></returns>
        public IMongoDatabase GetDb()
        {
            return Database;
        }
        /// <summary>
        /// 查询集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collName"></param>
        /// <returns></returns>
        public  IMongoCollection<T> GetCollection<T>(string collName)
        {
            return Database.GetCollection<T>(collName);
        }

        /// <summary>
        /// 获取指定数据库集合中的所有的文档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public List<T> FindAll<T>(string tableName)
        {
            List<T> list = new List<T>();
            try
            {
                var collection = GetCollection<T>(collName: tableName);
                FilterDefinition<T> filter = Builders<T>.Filter.Empty;
                list = collection.Find<T>(filter).ToList<T>();
            }
            catch (Exception ex)
            {
               
            }
            return list;
        }

        /// <summary>
        /// 插入单个文档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collName">集合名称</param>
        /// <param name="document">文档对象</param>
        public  int Insert<T>(string collName, T document)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                coll.InsertOne(document);
                return 1;
            }
            catch (Exception)
            {

                return 0;
            }

        }

        /// <summary>
        /// 插入多个文档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collName"></param>
        /// <param name="document"></param>
        public  int InsertMany<T>(string collName, List<T> document)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                coll.InsertMany(document);
                return document.Count;
            }
            catch (Exception)
            {

                return 0;
            }

        }

        /// <summary>
        /// 修改文档
        /// <para>示例 :修改id=3的,name改为oktool</para>
        /// <code>
        /// var eneity=Builders&lt;<paramref name="T"/>&gt;.Update.Set(p => p.Name, "oktool")
        /// ds.Update&lt;<paramref name="T"/>&gt;("qe", x => x.Id == 3,eneity)
        /// </code>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collName">集合名称</param>
        /// <param name="filter">修改条件</param>
        /// <param name="document">修改内容：</param>
        /// <param name="isUpsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
        /// <returns></returns>
        public int Update<T>(string collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> document, bool isUpsert = false)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                var result = coll.UpdateMany(filter, document, new UpdateOptions { IsUpsert = isUpsert });
                return (int)result.MatchedCount;
            }
            catch (Exception)
            {

                return 0;
            }

        }

        /// <summary>
        /// 用新对象替换新文档
        /// <code>ds.Update&lt;<paramref name="T"/>&gt;("qe", x => x.Id == 3, new dd { Id = 3, Name = "oktool" });</code>
        /// </summary>
        /// <param name="collName">集合名称</param>
        /// <param name="filter">修改条件</param>
        /// <param name="t">新对象</param>
        /// <param name="upsert">是否插入新文档（filter条件满足就更新，否则插入新文档）</param>
        /// <returns>修改影响文档数,异常返回0</returns>
        public int Update<T>(string collName, Expression<Func<T, Boolean>> filter, T t, Boolean upsert = false)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                BsonDocument document = t.ToBsonDocument<T>();
                document.Remove("_id");
                BsonDocument update = new BsonDocument("$set", document);
                var result = coll.UpdateMany(filter, update, new UpdateOptions { IsUpsert = upsert });
                return (int)result.ModifiedCount;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        /// <summary>
        /// 按BsonDocument条件删除
        /// <code>
        /// 清空集合:ds.Delete&lt;<paramref name="T"/>&gt;("qe",new MongoDB.Bson.BsonDocument { })
        /// </code>
        /// </summary>
        /// <param name="collName">集合名称</param>
        /// <param name="document">文档,</param>
        /// <returns>异常返回0</returns>
        public int Delete<T>(string collName, BsonDocument document)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                var result = coll.DeleteOne(document);
                return (int)result.DeletedCount ;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        /// <summary>
        /// 按条件表达式删除
        /// <code>
        /// ds.Delete&lt;<paramref name="T"/>&gt;("qe",x=>x.Id==2);
        /// </code>
        /// </summary>
        /// <param name="collName">集合名称</param>
        /// <param name="predicate">条件表达式</param>
        /// <returns>异常返回0</returns>
        public int Delete<T>(string collName, Expression<Func<T, Boolean>> predicate)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                var result = coll.DeleteOne(predicate);
                return (int)result.DeletedCount ;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        /// <summary>
        /// 按检索条件删除（建议用Builders-T构建复杂的查询条件）
        /// </summary>
        /// <param name="collName">集合名称</param>
        /// <param name="filter">条件</param>
        /// <returns></returns>
        public int Delete<T>(string collName, FilterDefinition<T> filter)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                var result = coll.DeleteOne(filter);
                return (int)result.DeletedCount;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        /// <summary>
        /// 查询，复杂查询直接用Linq处理
        /// </summary>
        /// <param name="collName">集合名称</param>
        /// <returns>要查询的对象</returns>
        public IQueryable<T> GetQueryable<T>(string collName)
        {
            try
            {
                var coll = GetCollection<T>(collName);
                return coll.AsQueryable<T>();
            }
            catch (Exception ex)
            {
                return null;
            }
        }





    }
}
